﻿using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;

namespace Jayden.Dll.Core.Persistence.Xml
{
	public class XmlDocumentLock
	{
		private static Dictionary<string, XmlDocumentLock> m_Instances = new Dictionary<string, XmlDocumentLock>();

		private XmlDocument m_Document;
		private string m_Filename;
		private ReaderWriterLock m_Lock = new ReaderWriterLock();

		public static XmlDocumentLock GetLock(string xmlPath)
		{
			lock (m_Instances)
			{
				XmlDocumentLock docLock = null;
				if (m_Instances.TryGetValue(xmlPath, out docLock))
					return docLock;
				XmlDocument document = new XmlDocument();
				if(File.Exists(xmlPath))
					document.Load(xmlPath);
				docLock = new XmlDocumentLock(xmlPath, document);
				m_Instances.Add(xmlPath, docLock);
				return docLock;
			}
		}

		private XmlDocumentLock(string filename, XmlDocument doc)
		{
			m_Document = doc;
			m_Filename = filename;
		}

		public XmlDocumentProxy GetDocument(bool writeAccess)
		{
			if (writeAccess)
				m_Lock.AcquireWriterLock(-1);
			else
				m_Lock.AcquireReaderLock(-1);
			return new XmlDocumentProxy(this, m_Document, writeAccess);
		}
		public XmlNodeProxy GetNode(string xpath, bool writeAccess)
		{
			if (writeAccess)
				m_Lock.AcquireWriterLock(-1);
			else
				m_Lock.AcquireReaderLock(-1);
			XmlNode node = null;
			if (string.IsNullOrWhiteSpace(xpath))
			{
				if (m_Document.DocumentElement == null)
				{
					node = m_Document.CreateElement("Root");
					m_Document.AppendChild(node);
				} else
					node = m_Document.DocumentElement;
			}
			else
				node = m_Document.SelectSingleNode(xpath);
			if (node == null)
			{
				ReleaseDocument(writeAccess);
				return null;
			}
			return new XmlNodeProxy(this, node, writeAccess);
		}

		public void ReleaseDocument(bool writeAccess)
		{
			if (writeAccess)
			{
				if (m_Document != null && m_Filename != null)
					m_Document.Save(m_Filename);
				m_Lock.ReleaseWriterLock();
			}
			else
				m_Lock.ReleaseReaderLock();
		}
	}
}
